using System;

namespace Extensions.RateLimiter.LeakyBucket
{
    /// <summary>
    /// 漏桶限流策略
    /// </summary>
    public class LeakyBucketThrottleStrategy
    {
        /// <summary>
        /// 限制数量
        /// </summary>
        private readonly long _limitCount;

        /// <summary>
        /// 间隔秒数
        /// </summary>
        private readonly int _intervalNanoSeconds;

        /// <summary>
        /// 速度
        /// </summary>
        private readonly long _rate;

        /// <summary>
        /// 已使用数量
        /// </summary>
        private long _usedCount;

        private long _lastTicks;

        public LeakyBucketThrottleStrategy(long limitCount, int intervalNanoSeconds)
        {
            _limitCount = limitCount;
            _intervalNanoSeconds = intervalNanoSeconds;
            _rate = _limitCount / Convert.ToInt64(intervalNanoSeconds);
            _usedCount = 0;
            _lastTicks = DateTime.Now.Ticks;
        }

        public bool IsLimit(int n = 1)
        {
            var nowTicks = DateTime.Now.Ticks;

            //计算剩余水量
            _usedCount = Math.Max(0, _usedCount - (nowTicks - _lastTicks) * _rate);
            _lastTicks = nowTicks;
            if (_usedCount + n >= _limitCount)
            {
                return false;
            }

            _usedCount += n;
            return true;
        }
    }
}